package com.dc.juc.example._3_atomic;

import com.dc.juc.annoations.ThreadSafe;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;

/**
 * Description: AtomicIntegerFieldUpdater
 *  基于反射的实用工具，可以对指定类的指定 volatile int 字段进行原子更新。此类用于原子数据结构，该结构中同一节点的几个字段都独立受原子更新控制。
 *
 *  说明：
 *      【1】字段必须是volatile类型的，在线程之间共享变量时保证立即可见. volatile int value = 3
 *      【2】字段的描述类型（修饰符public/protected/default/private）是与调用者与操作对象字段的关系一致。
 *          也就是说调用者能够直接操作对象字段，那么就可以反射进行原子操作。但是对于父类的字段，子类是不能直接操作的，尽管子类可以访问父类的字段
 *      【3】只能是实例变量，不能是类变量，也就是说不能加static关键字。
 *      【4】只能是可修改变量，不能使final变量，因为final的语义就是不可修改。实际上final的语义和volatile是有冲突的，这两个关键字不能同时存在。
 *      【5】对于AtomicIntegerFieldUpdater和AtomicLongFieldUpdater只能修改int/long类型的字段，不能修改其包装类型（Integer/Long）。
 *          如果要修改包装类型就需要使用AtomicReferenceFieldUpdater。
 *
 *  使用场景：
 *      【1】多数用到这个字段的代码是在读取字段的值, 但仍然有通过CAS更新字段值的需求.
 *          这个时候用AtomicInteger的话每个直接读取这个字段的地方都要多一次.get()调用, 用volatile又满足不了需求,
 *          所以就用到了AtomicIntegerFieldUpdater
 *      【2】这个字段所属的类会被创建大量的实例对象, 如果用AtomicInteger, 每个实例里面都要创建AtomicInteger对象, 从而多出内存消耗.
 *          比如一个链表类的Node, 用AtomicReference保存next显然是不合适的.
 *
 * @author: gdc
 * @date: 2021/8/2
 * @version 1.0
 */
@Slf4j
@ThreadSafe
public class _6_AtomicIntegerFieldUpdater {

    private static AtomicIntegerFieldUpdater<_6_AtomicIntegerFieldUpdater> updater =
            AtomicIntegerFieldUpdater.newUpdater(_6_AtomicIntegerFieldUpdater.class, "COUNT");

    /**
     * 变量属于实例变量，被volatile修饰，且不能final修饰
     */
    @Getter
    private volatile int COUNT = 100;

    public static void main(String[] args){
        _6_AtomicIntegerFieldUpdater fieldUpdater = new _6_AtomicIntegerFieldUpdater();

        if (updater.compareAndSet(fieldUpdater, 100, 200)){
            log.info("update success 1, {}", fieldUpdater.COUNT);
        }

        if (updater.compareAndSet(fieldUpdater, 100, 200)){
            log.info("update success 2, {}", fieldUpdater.COUNT);
        } else {
            log.info("update failed 3, {}", fieldUpdater.COUNT);
        }
    }
}
